home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-10-16 | 13.7 KB | 613 lines | [TEXT/MPS ] |
- /*------------------------------------------------------------------------------------------
-
- Program: CPlusTESample 2.0AE
- File: Application.cp
- Uses: Application.h
- Document.h
-
- by Andrew Shebanow
- of Apple Macintosh Developer Technical Support
- with modifications by Eric Berdahl
-
- Copyright © 1989-1990 Apple Computer, Inc.
- Copyright © 1992 Eric Berdahl
- All rights reserved.
-
- ------------------------------------------------------------------------------------------*/
-
- // Mac Includes
- #ifndef __TYPES__
- #include <Types.h>
- #endif
- #ifndef __QUICKDRAW__
- #include <QuickDraw.h>
- #endif
- #ifndef __FONTS__
- #include <Fonts.h>
- #endif
- #ifndef __EVENTS__
- #include <Events.h>
- #endif
- #ifndef __CONTROLS__
- #include <Controls.h>
- #endif
- #ifndef __WINDOWS__
- #include <Windows.h>
- #endif
- #ifndef __RESOURCES__
- #include <Resources.h>
- #endif
- #ifndef __MENUS__
- #include <Menus.h>
- #endif
- #ifndef __TEXTEDIT__
- #include <TextEdit.h>
- #endif
- #ifndef __DIALOGS__
- #include <Dialogs.h>
- #endif
- #ifndef __DESK__
- #include <Desk.h>
- #endif
- #ifndef __SCRAP__
- #include <Scrap.h>
- #endif
- #ifndef __TOOLUTILS__
- #include <ToolUtils.h>
- #endif
- #ifndef __MEMORY__
- #include <Memory.h>
- #endif
- #ifndef __SEGLOAD__
- #include <SegLoad.h>
- #endif
- #ifndef __FILES__
- #include <Files.h>
- #endif
- #ifndef __OSUTILS__
- #include <OSUtils.h>
- #endif
- #ifndef __TRAPS__
- #include <Traps.h>
- #endif
-
- #ifndef __APPLICATION__
- #include "Application.h"
- #endif
-
- #ifndef __DOCUMENT__
- #include "Document.h"
- #endif
-
- // OSEvent is the event number of the suspend/resume and mouse-moved events sent
- // by MultiFinder. Once we determine that an event is an osEvent, we look at the
- // high byte of the message sent to determine which kind it is. To differentiate
- // suspend and resume events we check the resumeMask bit.
- const short kOsEvent = app4Evt; // event used by MultiFinder
- const short kSuspendResumeMessage = 0x01; // high byte of suspend/resume event message
- const short kClipConvertMask = 0x02; // bit of message field clip conversion
- const short kResumeMask = 0x01; // bit of message field for resume vs. suspend
- const short kMouseMovedMessage = 0xFA; // high byte of mouse-moved event message
-
- extern "C" {
- // from MPW standard library
- void _DataInit(); // sets up A5 globals
- };
-
- // useful state checking Boolean
- Boolean gHaveColorQD;
-
- // just as "normal" global variables that are declared extern in
- // header files must still be declared somewhere in order to reserve
- // space, static class variables must also be declared outside of
- // the class definition. The syntax is confusing, but then, thats
- // what makes C++ so ***interesting***.
- OSType TApplication::fCreator;
- Boolean TApplication::fHaveWaitNextEvent;
- Boolean TApplication::fOnSystem7;
- TApplication* TApplication::gApplication = nil;
-
- TApplication::TApplication(OSType creator)
- {
- SysEnvRec envRec;
- long stkNeeded;
- long heapSize;
-
- // initialize the global application variable
- gApplication = this;
-
- // initialize Mac Toolbox components
- InitGraf((Ptr) &qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs((ResumeProcPtr) nil);
- InitCursor();
-
- // Unload data segment: note that _DataInit must not be in Main!
- UnloadSeg((ProcPtr) _DataInit);
-
- // ignore the error returned from SysEnvirons; even if an error occurred,
- // the SysEnvirons glue will fill in the SysEnvRec
- (void) SysEnvirons(curSysEnvVers, &envRec);
-
- // Are we running on a 128K ROM machine or better???
- if (envRec.machineType < 0)
- BigBadError(kErrStrings,eWrongMachine); // if not, alert & quit
-
- gHaveColorQD = envRec.hasColorQD;
-
- fOnSystem7 = (envRec.systemVersion >= 0x0700);
-
- // if we need more stack space, get it now
- stkNeeded = StackNeeded();
- if (stkNeeded > StackSpace())
- {
- // new address is heap size + current stack - needed stack
- SetApplLimit((Ptr) ((long) GetApplLimit() - stkNeeded + StackSpace()));
- }
-
- // Check for minimum heap size
- heapSize = (long) GetApplLimit() - (long) ApplicZone();
- if (heapSize < HeapNeeded())
- BigBadError(kErrStrings,eSmallSize);
-
- // expand the heap so new code segments load at the top
- MaxApplZone();
-
- // allocate an empty document list
- fDocList = new TDocumentList;
-
- // check to see if WaitNextEvent is implemented
- fHaveWaitNextEvent = TrapAvailable(_WaitNextEvent, ToolTrap);
-
- // initialize our class variables
- fCurDoc = nil;
- fDone = false;
- fInBackground = false;
- fMouseRgn = nil;
- fWhichWindow = nil;
- fCreator = creator;
- }
-
-
- TApplication* TApplication::GetApplication()
- {
- return gApplication;
- }
-
-
- void TApplication::EventLoop()
- {
- int gotEvent;
- EventRecord tEvt;
-
- SetUp(); // call setup routine
- DoIdle(); // do idle once
-
- while (!fDone)
- {
- // always set up fWhichWindow before doing anything
- fWhichWindow = FrontWindow();
- if (fWhichWindow != nil)
- {
- // see if window belongs to a document
- fCurDoc = fDocList->FindDoc(fWhichWindow);
- // make sure we always draw into correct window
- SetPort(fWhichWindow);
- }
- else fCurDoc = nil;
-
- DoIdle(); // call idle time handler
-
- if (fHaveWaitNextEvent)
- gotEvent = WaitNextEvent(everyEvent, &tEvt, SleepVal(), fMouseRgn);
- else
- {
- SystemTask();
- gotEvent = GetNextEvent(everyEvent, &tEvt);
- }
- fTheEvent = tEvt;
-
- // if we got a real event, process it
- if (gotEvent)
- ProcessEvent();
-
- AdjustCursor();
- }
- }
-
- void TApplication::ProcessEvent()
- {
- // make sure alert is loaded in memory BEFORE we do any event
- // processing. This is necessary since the alert for the case
- // when we need to display an out of memory alert.
- CouldAlert(rUserAlert);
- TRY
- {
- AdjustCursor();
- switch (fTheEvent.what)
- {
- case mouseDown:
- DoMouseDown();
- break;
- case mouseUp:
- DoMouseUp();
- break;
- case keyDown:
- case autoKey:
- DoKeyDown();
- break;
- case updateEvt:
- DoUpdateEvt();
- break;
- case diskEvt:
- DoDiskEvt();
- break;
- case activateEvt:
- DoActivateEvt();
- break;
- case kOsEvent:
- DoOSEvent();
- break;
- case kHighLevelEvent:
- DoHighLevelEvent();
- break;
- default:
- break;
- }
- }
- RECOVER
- {
- AlertUser((short) gFailMessage, gFailError);
- // don't let error bubble up any farther
- goto doneEvent;
- }
- ENDTRY
-
- doneEvent:
- return;
- }
-
- void TApplication::DoHighLevelEvent()
- {
- FailOSErr(AEProcessAppleEvent(&fTheEvent));
- }
-
- void TApplication::DoKeyDown()
- {
- char key;
- long mResult;
-
- key = (char) (fTheEvent.message & charCodeMask);
- if ((fTheEvent.modifiers & cmdKey) && (fTheEvent.what == keyDown))
- {
- // only do command keys if we are not autokeying
- AdjustMenus(); // make sure menus are up to date
- mResult = MenuKey(key);
- if (mResult != 0) // if it wasn't a menu key, pass it through
- {
- DoMenuCommand(HiWord(mResult), LoWord(mResult));
- return;
- }
- }
- if (fCurDoc != nil)
- {
- EventRecord tEvt;
-
- // we copy event record so that we don't pass reference to object field
- tEvt = fTheEvent;
- fCurDoc->DoKeyDown(&tEvt);
- }
- }
-
- void TApplication::DoActivateEvt()
- {
- // event record contains window ptr
- fWhichWindow = (WindowPtr) fTheEvent.message;
- // see if window belongs to a document
- fCurDoc = fDocList->FindDoc(fWhichWindow);
- SetPort(fWhichWindow);
-
- if (fCurDoc != nil)
- fCurDoc->DoActivate((fTheEvent.modifiers & activeFlag) != 0);
- }
-
- void TApplication::DoUpdateEvt()
- {
- // event record contains window ptr
- fWhichWindow = (WindowPtr) fTheEvent.message;
- // see if window belongs to a document
- fCurDoc = fDocList->FindDoc(fWhichWindow);
- SetPort(fWhichWindow);
-
- if (fCurDoc != nil)
- fCurDoc->DoUpdate();
- }
-
- // NOTE: we use an anonymous parameter here so that the compiler
- // doesn't warn us about it being unused. Since we give it a name
- // in the class definition, we still know what its used for.
- void TApplication::DoSuspend(Boolean)
- {
- if (fCurDoc != nil)
- fCurDoc->DoActivate(!fInBackground);
- }
-
- void TApplication::DoResume(Boolean)
- {
- if (fCurDoc != nil)
- fCurDoc->DoActivate(!fInBackground);
- }
-
- void TApplication::DoOSEvent()
- {
- Boolean doConvert;
- unsigned char evType;
-
- // is it a multifinder event?
- evType = (unsigned char) (fTheEvent.message >> 24) & 0x00ff;
- switch (evType) { // high byte of message is type of event
- case kMouseMovedMessage:
- DoIdle(); // mouse-moved is also an idle event
- break;
- case kSuspendResumeMessage:
- doConvert = (fTheEvent.message & kClipConvertMask) != 0;
- fInBackground = (fTheEvent.message & kResumeMask) == 0;
- if (fInBackground)
- DoSuspend(doConvert);
- else DoResume(doConvert);
- break;
- }
- }
-
- void TApplication::DoMouseDown()
- {
- long mResult;
- short partCode;
- WindowPtr tWind;
- EventRecord tEvt;
-
- // gotta watch those object field dereferences
- partCode = FindWindow(fTheEvent.where, &tWind);
- fWhichWindow = tWind;
- tEvt = fTheEvent;
- switch (partCode)
- {
- case inSysWindow:
- DoMouseInSysWindow();
- break;
- case inMenuBar:
- AdjustMenus();
- mResult = MenuSelect(tEvt.where);
- if (mResult != 0)
- DoMenuCommand(HiWord(mResult),LoWord(mResult));
- break;
- case inGoAway:
- DoGoAway();
- break;
- case inDrag:
- DoDrag();
- break;
- case inGrow:
- if (fCurDoc != nil)
- fCurDoc->DoGrow(&tEvt);
- break;
- case inZoomIn:
- case inZoomOut:
- if ((TrackBox(fWhichWindow, tEvt.where, partCode)) &&
- (fCurDoc != nil))
- fCurDoc->DoZoom(partCode);
- break;
- case inContent:
- // If window is not in front, make it so
- if ( fWhichWindow != FrontWindow() )
- SelectWindow(fWhichWindow);
- else if (fCurDoc != nil)
- fCurDoc->DoContent(&tEvt);
- break;
- }
- }
-
- void TApplication::DoDrag()
- {
- DragWindow(fWhichWindow, fTheEvent.where, &qd.screenBits.bounds);
- }
-
- void TApplication::DoGoAway()
- {
- if (TrackGoAway(fWhichWindow, fTheEvent.where))
- {
- if (fCurDoc != nil)
- {
- if (fCurDoc->DoClose(true, yesResult, false) != cancelResult)
- {
- fDocList->RemoveDoc(fCurDoc);
- delete fCurDoc;
- }
- }
- else CloseDeskAcc(((WindowPeek) fWhichWindow)->windowKind);
- // make sure our current document/window references are valid
- fWhichWindow = FrontWindow();
- if (fWhichWindow != nil)
- {
- fCurDoc = fDocList->FindDoc(fWhichWindow);
- SetPort(fWhichWindow);
- }
- else fCurDoc = nil;
- }
- }
-
- void TApplication::ProcessArgs()
- {
- if (!fOnSystem7)
- {
- short message, numFiles, curFile;
- AppFile fileInfo;
-
- /* count the files */
- CountAppFiles(&message,&numFiles);
- if (numFiles == 0)
- {
- // create a single empty document
- DoNew();
- return;
- }
- for (curFile = 1; curFile <= numFiles; curFile++)
- {
- /* get file info */
- GetAppFiles(curFile,&fileInfo);
- /* open/print the file */
- if (message != appPrint)
- {
- TRY
- {
- OpenADoc(fileInfo.vRefNum,0,fileInfo.fName,fileInfo.fType);
- }
- RECOVER
- {
- goto processNextFile;
- }
- ENDTRY
- }
- processNextFile:
- /* clear finder arg for this file */
- ClrAppFiles(curFile);
- }
- }
- }
-
- void TApplication::DoQuit(Boolean askUser, YNCResult defaultResult)
- {
- while (true)
- {
- fWhichWindow = FrontWindow();
- if (fWhichWindow == nil)
- break;
- fCurDoc = fDocList->FindDoc(fWhichWindow);
- if (fCurDoc != nil)
- {
- // if the user cancels the quit
- if (fCurDoc->DoClose(askUser, defaultResult, true) == cancelResult)
- return;
- else
- {
- fDocList->RemoveDoc(fCurDoc);
- delete fCurDoc;
- }
- }
- else CloseDeskAcc(((WindowPeek) fWhichWindow)->windowKind);
- // make sure we aren't in an infinite loop. This could occur
- // if the CloseDeskAcc was failing for some reason.
- if (FrontWindow() == fWhichWindow)
- {
- // send the window to the back of the list.
- // if the FrontWindow is still the same, we will exit
- // the loop. Otherwise, we let the loop keep running so
- // that we have a chance to close our other windows
- // cleanly
- SendBehind(fWhichWindow, nil);
- if (FrontWindow() == fWhichWindow)
- break;
- }
- }
- fDone = true;
- fWhichWindow = nil;
- fCurDoc = nil;
- }
-
- Boolean TApplication::TrapAvailable(short tNumber,TrapType tType)
- {
- // Check and see if the trap exists. On 64K ROM machines, tType will be ignored.
- return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
- }
-
- void TApplication::WDToDirID(short wdRefNum, short& vRefNum, long& dirID)
- {
- const short kRootDirID = 2;
- long junk;
-
- OSErr err = GetWDInfo(wdRefNum,&vRefNum,&dirID,&junk);
- if (err != noErr)
- {
- vRefNum = wdRefNum; // if GetVol doesn't return valid vRefNum/dirID pair,
- dirID = kRootDirID; // use wdRefNum as a vRefNum and use root for dirID
- }
- }
-
- void AlertUser(short errResID, short errCode)
- {
- Str255 messageStr;
-
- // if we have a hilited menu, turn it off before displaying alert
- HiliteMenu(0);
-
- if (errResID != 0)
- {
- GetIndString(messageStr, errResID, errCode);
- ParamText(messageStr, "\p", "\p", "\p");
- }
- else
- {
- // we need to lookup the error in our table
- LookupErrorString(errCode,kSysErrStrings,messageStr);
- ParamText(messageStr, "\p", "\p", "\p");
- }
- SetCursor(&qd.arrow);
- (void) Alert(rUserAlert, (ModalFilterProcPtr) nil);
- }
-
- void BigBadError(short errResID, short errCode)
- {
- AlertUser(errResID,errCode);
- ExitToShell();
- }
-
- Boolean LookupErrorString(short value, short resID, StringPtr str)
- {
- struct ErrRecord {
- short lowErr;
- short highErr;
- short index;
- };
- typedef struct ErrRecord* ErrRecordPtr;
-
- Handle table;
- ErrRecordPtr pEntry;
- unsigned long tableOffset;
- long lenTab;
- int strID;
-
- // start with an empty string
- str[0] = 0;
-
- table = GetResource('errs', resID);
- if (!table)
- {
- lenTab = (long) (GetHandleSize((Handle) table) / sizeof(ErrRecord));
-
- strID = 0;
- tableOffset = 0;
-
- for (long i = 1; i <= lenTab; i++)
- {
- pEntry = (ErrRecordPtr) ((unsigned long) *table) + tableOffset;
-
- if (pEntry->lowErr == 0)
- strID = pEntry->index;
- else if ((pEntry->lowErr <= value) && (value <= pEntry->highErr))
- {
- if (pEntry->index > 0)
- GetIndString(str, strID, pEntry->index);
- return true;
- }
-
- tableOffset += sizeof(ErrRecord);
- }
- }
- return false;
- }
-
- // That's all, folks...
-